#include <iostream>
#include <memory>

using std::cout;
using std::shared_ptr;
using std::unique_ptr;

class Point {
public:
  double x;
  double y;
  double z;
  Point() = default;
  ~Point() {
    x = 1;
    cout << "point released" << std::endl;
  }
};

Point FunReturnValue() {
  Point p;

  p.x = 100;
  cout << &p << std::endl;
  return p;
}

void DemoForValue() {

  cout << "value" << std::endl;
  Point p = FunReturnValue();
  cout << &p << std::endl;
  cout << p.x << std::endl;
}

Point *FunReturnPointer() {
  auto p = new Point();

  p->x = 100;
  cout << p << std::endl;
  return p;
}

void DemoForPointer() {
  Point *p = FunReturnPointer();
  cout << p << std::endl;
  cout << p->x << std::endl;
  delete p;
}

shared_ptr<Point> FunReturnSharedPointer() {
  shared_ptr<Point> p;
  p.reset(new Point());

  p->x = 100;
  cout << p << std::endl;
  return p;
}

void DemoForSharedPointer() {
  shared_ptr<Point> p = FunReturnSharedPointer();
  cout << p << std::endl;
  cout << p->x << std::endl;
}

unique_ptr<Point> FunReturnUniquePointer() {
  auto p = std::make_unique<Point>();

  p->x = 100;
  cout << p << std::endl;
  return p;
}

void DemoForUniquePointer() {
  unique_ptr<Point> p = FunReturnUniquePointer();
  cout << p << std::endl;
  cout << p->x << std::endl;
}

int main() {
  DemoForValue();
  DemoForPointer();
  DemoForSharedPointer();
  DemoForUniquePointer();
  return 0;
}